home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK1.toast / Development Kits (Disc 1) / Open Transport / OT1.1 Developer Release / Open Transport SDK / Open Tpt Client Developer / Samples / Serial / SerialSample.cp next >
Encoding:
Text File  |  1996-11-19  |  20.4 KB  |  928 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        SerialSample.cp
  3.  
  4.     Contains:    Sample program for a Serial endpoint
  5.  
  6.     Copyright:    © 1992-1995 by Apple Computer, Inc., all rights reserved.
  7.  
  8. */
  9.  
  10. //
  11. // We want to use the OT 'new' operator, not the standard MPW one, so include
  12. // OpenTptGlobalNew.h first.
  13. //
  14. #ifndef __OPENTPTGLOBALNEW__
  15. #include <OpenTptGlobalNew.h>
  16. #endif
  17. #ifndef __OPENTPTSERIAL__
  18. #include <OpenTptSerial.h>
  19. #endif
  20.  
  21. #ifndef __STDIO__
  22. #include <stdio.h>
  23. #endif
  24. #ifndef __EVENTS__
  25. #include <Events.h>
  26. #endif
  27. #ifndef __MENUS__
  28. #include <Menus.h>
  29. #endif
  30. #ifndef __DESK__
  31. #include <Desk.h>
  32. #endif
  33.  
  34. /*******************************************************************************
  35. ** GlobalVariables
  36. ********************************************************************************/
  37.  
  38. struct StateInfo
  39. {
  40.     TEndpoint*        endPt;
  41.     long            sysTaskRef;
  42.     OSStatus        error;
  43.     Boolean            lastWasCR;
  44.     UInt8            prevCR;
  45.     Boolean            ready;
  46.     Boolean            unbound;
  47.     Boolean            disconnected;
  48.     Boolean            connect;
  49.     Boolean            scheduled;
  50.     Boolean            optMgmtDone;
  51.     Boolean            ioctlDone;
  52.     Boolean            acceptDone;
  53.     Boolean            passconDone;
  54. };
  55.  
  56. /*******************************************************************************
  57. ** SerialProcessProc
  58. ********************************************************************************/
  59.  
  60. pascal void SerialProcessProc(void* contextPtr)
  61. {
  62.     StateInfo*    info = (StateInfo*)contextPtr;
  63.     OTResult    result;
  64.     UInt8        buf[256];
  65.     
  66.     info->scheduled = false;
  67.     while ( true )
  68.     {
  69.         OTFlags    flags;
  70.         result = OTRcv(info->endPt, buf, 256, &flags);
  71.         if ( result < 0 )
  72.         {
  73.             if ( result != kOTNoDataErr )
  74.                 DebugStr("\pError in Rcv");
  75.             break;
  76.         }
  77.         else
  78.         {
  79.             OTResult    idx;
  80.             //
  81.             //    The wierdness with 0x0a and 0x0d is to try to be system-independent
  82.             //    of how CR/LF pairs happen.  If either character is received, if the
  83.             //  previous character was not an 0x0a or 0x0d, then we output the CR/LF,
  84.             //  and flag that the last was a CR, and remember which it was.
  85.             //  If the previous CR/LF character was the same one as our current
  86.             //  character, then this is a new CR/LF.  The jist of all of this is
  87.             //  that if we get an 0x0a or 0x0d, if the next character is the
  88.             //  other one, we will ignore it.
  89.             //
  90.             for ( idx = 0; idx < result; ++idx )
  91.             {
  92.                 UInt8 c = buf[idx];
  93.                 if ( c >= 0x20 && c <= 0x7f )
  94.                 {
  95.                     info->lastWasCR = false;
  96.                     printf("%c", c);
  97.                 }
  98.                 else if ( c == 0x0a || c == 0x0d )
  99.                 {
  100.                     if ( !info->lastWasCR || info->prevCR == c )
  101.                     {
  102.                         info->lastWasCR = true;
  103.                         info->prevCR = c;
  104.                         printf("\n");
  105.                     }
  106.                     else
  107.                         info->lastWasCR = false;
  108.                 }
  109.                 else
  110.                 {
  111.                     info->lastWasCR = false;
  112.                     printf("\\x%02X", c);
  113.                 }
  114.             }
  115.             fflush(stdout);
  116.         }
  117.     }
  118. }
  119.  
  120. /*******************************************************************************
  121. ** Event handler...
  122. ********************************************************************************/
  123.  
  124. pascal void SerialEventHandler(void* contextPtr, OTEventCode code,
  125.                                OTResult result, void* /* cookie */)
  126. {
  127.     register StateInfo* info = (StateInfo*)contextPtr;
  128.     
  129.     switch ( code )
  130.     {
  131.         //
  132.         // We could poll for the data in our simple example here, but if we were doing
  133.         // more complex things than just scanning the keyboard for keys, that would
  134.         // be inconvient.  By using the OTScheduleSystemTask, we can read our characters
  135.         // at SystemTask time, and then output them however we want to.
  136.         //
  137.         case T_DATA:
  138.         {
  139.             OTScheduleSystemTask(info->sysTaskRef);
  140.             break;
  141.         }
  142.         
  143.         case T_GODATA:
  144.             break;
  145.         //
  146.         // Our Bind is completing - if it succeeded, issue a Connect() if we are supposed
  147.         // to be connecting.  Otherwise, just sit tight until we get a T_LISTEN event that
  148.         // indicates someone is trying to talk to us on the serial port.
  149.         //
  150.         case T_BINDCOMPLETE:
  151.         {
  152.             if ( result != kOTNoError )
  153.             {
  154.                 DebugStr("\pAsync Bind failed.");
  155.                 info->error = (OSStatus)result;
  156.             }
  157.             else
  158.                 info->unbound = false;
  159.                 
  160.             if ( info->connect )
  161.             {
  162.                 TCall    req;
  163.                 
  164.                 req.addr.buf    = NULL;
  165.                 req.addr.len    = 0;
  166.                 req.opt.buf        = NULL;
  167.                 req.opt.len        = 0;
  168.                 req.udata.buf    = NULL;
  169.                 req.udata.len    = 0;
  170.  
  171.                 info->error = OTConnect(info->endPt, &req, NULL);
  172.             }
  173.             if ( info->error != kOTNoError )
  174.                 info->ready = true;
  175.             break;
  176.         }
  177.         //
  178.         // Unbind is complete
  179.         //
  180.         case T_UNBINDCOMPLETE:
  181.         {
  182.             if ( result != 0 )
  183.                 DebugStr("\pAsync Bind failed.");
  184.             info->error        = (OSErr)result;
  185.             info->unbound    = true;
  186.             break;
  187.         }
  188.         
  189.         case kStreamIoctlEvent:
  190.         {
  191.             if ( result != 0 )
  192.                 DebugStr("\pIOCTL call failed.");
  193.             info->ioctlDone    = true;
  194.             break;
  195.         }
  196.         //
  197.         // An Option Management call is complete
  198.         //
  199.         case T_OPTMGMTCOMPLETE:
  200.         {
  201.             if ( result != 0 )
  202.                 DebugStr("\pOption Management call failed.");
  203.             info->optMgmtDone    = true;
  204.             break;
  205.         }
  206.         //
  207.         // a SndDisconnect has completed.  If info->error is not kOTNoError, then we
  208.         // did the disconnect because of an error, so let's not overwrite the error.
  209.         // Then, let's do an unbind.
  210.         //
  211.         case T_DISCONNECTCOMPLETE:
  212.         {
  213.             if ( result != 0 )
  214.                 DebugStr("\pAsync disconnect failed.");
  215.             if ( info->error == kOTNoError )
  216.                 info->error = (OSStatus)result;
  217.             info->disconnected    = true;
  218.             OTUnbind(info->endPt);
  219.             break;
  220.         }
  221.         //
  222.         // Our connect request is complete, do a RcvConnect if all is well.
  223.         //
  224.         case T_CONNECT:
  225.         {
  226.             if ( result != 0 )
  227.                 DebugStr("\pAsync connect failed.");
  228.             info->error = (OSErr)result;
  229.             
  230.             if ( info->error == kOTNoError )
  231.             {
  232.                 TCall retCall;
  233.                 
  234.                 retCall.addr.buf    = NULL;
  235.                 retCall.addr.maxlen    = 0;
  236.                 retCall.opt.buf        = NULL;
  237.                 retCall.opt.maxlen    = 0;
  238.                 retCall.udata.buf    = NULL;
  239.                 retCall.udata.maxlen= 0;
  240.             
  241.                 info->error = OTRcvConnect(info->endPt, &retCall);
  242.             }
  243.             info->ready = true;
  244.             break;
  245.         }
  246.         //
  247.         // Our Accept is complete - we're ready for action!
  248.         //
  249.         case T_ACCEPTCOMPLETE:
  250.         {    
  251.             info->acceptDone = true;
  252.             if ( result != kOTNoError )
  253.             {
  254.                 DebugStr("\pAsync accept failed.");
  255.                 info->error = (OSErr)result;
  256.                 info->ready = true;
  257.             }
  258.             else if ( info->passconDone )
  259.             {
  260.                 info->error = kOTNoError;
  261.                 info->ready = true;
  262.             }
  263.             break;
  264.         }
  265.         //
  266.         // Our endpoint is now ready for action - we've got a connection
  267.         //
  268.         case T_PASSCON:
  269.         {
  270.             //
  271.             // T_PASSCON's can't have an error
  272.             //
  273.             info->passconDone;
  274.             if ( info->acceptDone )
  275.             {
  276.                 info->error = kOTNoError;
  277.                 info->ready = true;
  278.             }
  279.             break;
  280.         }
  281.         //
  282.         // We have an incoming connection request.  We do a Listen to get the information
  283.         // on the request (for Serial connections, this is really a formality, but...)
  284.         // then issue an Accept() on the same endpoint.
  285.         // If something goes wrong, we issue a SndDisconnect(), which has the effect of
  286.         // rejecting the connection request.
  287.         //
  288.         case T_LISTEN:
  289.         {
  290.             TCall    lCall;
  291.             
  292.             lCall.addr.buf        = NULL;
  293.             lCall.addr.maxlen    = 0;
  294.             lCall.opt.buf        = NULL;
  295.             lCall.opt.maxlen    = 0;
  296.             lCall.udata.buf        = NULL;
  297.             lCall.udata.maxlen    = 0;
  298.  
  299.             info->error = OTListen(info->endPt, &lCall);
  300.             if ( info->error != kOTNoError )
  301.                 info->ready = true;
  302.             else
  303.             {
  304.                 TCall*    aCall = new TCall;
  305.                 if ( aCall == NULL )
  306.                 {
  307.                     info->error = kOTOutOfMemoryErr;
  308.                     info->ready = true;
  309.                     OTSndDisconnect(info->endPt, NULL);
  310.                     break;
  311.                 }
  312.                 aCall->addr.buf        = NULL;    // Accept doesn't look at or use the "addr" field
  313.                 aCall->addr.maxlen    = 0;
  314.                 aCall->opt.buf        = NULL;
  315.                 aCall->opt.len        = 0;
  316.                 aCall->udata.buf    = NULL;
  317.                 aCall->udata.len    = 0;
  318.                 aCall->sequence = lCall.sequence;
  319.                 info->error = OTAccept(info->endPt, info->endPt, aCall);
  320.                 if ( info->error != kOTNoError )
  321.                 {
  322.                     delete aCall;
  323.                     info->ready = true;
  324.                     OTSndDisconnect(info->endPt, NULL);
  325.                 }
  326.             }
  327.             break;
  328.         }
  329.         
  330.         default:
  331.             DebugStr("\pUnknown or unexpected event");
  332.             break;
  333.     }
  334. }
  335.  
  336. /*******************************************************************************
  337. ** ShowEndpointOptions
  338. ********************************************************************************/
  339.  
  340. void ShowEndpointOptions(StateInfo* info, Boolean* isBreakOn)
  341. {
  342.     OSStatus    err;
  343.     TOptMgmt*    ret = (TOptMgmt*)OTAlloc(info->endPt, T_OPTMGMT, T_OPT, &err);
  344.  
  345.     
  346.     printf("Current Settings for endpoint @ %08lX:\n", (long)info->endPt);
  347.     
  348.     do
  349.     {
  350.         if ( ret == NULL )
  351.         {
  352.             printf("ERROR: could not allocate TOptMgmt structure (%d)\n", err);
  353.             fflush(stdout);
  354.             break;
  355.         }
  356.         //
  357.         // Get the current options
  358.         //
  359.         TOptMgmt        req;
  360.         TOptionHeader    option;
  361.         
  362.         option.len        = kOTOptionHeaderSize;
  363.         option.level    = COM_SERIAL;
  364.         option.name        = T_ALLOPT;
  365.         
  366.         req.opt.buf = (UInt8*)&option;
  367.         req.opt.len    = kOTOptionHeaderSize;
  368.         req.flags    = T_CURRENT;
  369.         
  370.         info->optMgmtDone = false;
  371.         err = OTOptionManagement(info->endPt, &req, ret);
  372.         if ( err != kOTNoError )
  373.         {
  374.             printf("ERROR: OptionManagement T_CURRENT request returned %d\n", err);
  375.             break;
  376.         }
  377.         while ( !info->optMgmtDone )
  378.             ;
  379.         //
  380.         // Now, let's print the options
  381.         //
  382.         {
  383.             TOption*    opt = (TOption*)ret->opt.buf;
  384.             char        string[512];
  385.  
  386.             err = OTCreateOptionString(kSerialName, &opt, ret->opt.buf + ret->opt.len,
  387.                                        string, sizeof(string));
  388.             
  389.             if ( err == kOTNoError )
  390.             {
  391.                 char*    str = string;
  392.                 size_t    len = 0;
  393.                 while ( true )
  394.                 {
  395.                     char* temp = strchr(str, ',');
  396.                     if ( temp == NULL )
  397.                     {
  398.                         printf("%s\n", str);
  399.                         break;
  400.                     }
  401.                     if ( len + temp - str + 1 > 60 )
  402.                     {
  403.                         printf("\n");
  404.                         if ( *str == ' ' )
  405.                             str += 1;
  406.                         len = 0;
  407.                     }
  408.                     printf("%*.*s", temp - str + 1, temp - str + 1, str);
  409.                     len += temp - str + 1;
  410.                     str = temp + 1;
  411.                 }
  412.                 fflush(stdout);
  413.             }
  414.         }
  415.         
  416.         TOption* opt =  OTFindOption(ret->opt.buf, ret->opt.len, COM_SERIAL, SERIAL_OPT_STATUS);
  417.             
  418.         if ( opt != NULL )
  419.         {
  420.             if ( !(*(UInt32*)opt->value & kOTSerialOutputBreakOn) )
  421.                 *isBreakOn = false;
  422.             else
  423.                 *isBreakOn = true;
  424.         }
  425.         else
  426.             printf("ERROR:OptionManagement did not have SERIAL_OPT_STATUS in returned options\n");
  427.     } while ( false );
  428.     fflush(stdout);    
  429.     OTFree(ret, T_OPTMGMT);
  430. }
  431.  
  432. /*******************************************************************************
  433. ** DoBreak
  434. ********************************************************************************/
  435.  
  436. void DoBreak(StateInfo* info, Boolean* breakOn, Boolean timed)
  437. {
  438.     UInt32        value;
  439.     OSStatus    err;
  440.  
  441.     
  442.     if ( timed )
  443.         value = 5000;
  444.     else if ( *breakOn )
  445.         value = kOTSerialSetBreakOff;
  446.     else
  447.         value = kOTSerialSetBreakOn;
  448.  
  449.     err = OTIoctl(info->endPt, I_SetSerialBreak, (void*)value);
  450.  
  451.     if ( err != kOTNoError )
  452.         printf("ERROR: OptionManagement T_NEGOTIATE request returned %d\n", err);
  453.     else
  454.     {
  455.         while ( !info->ioctlDone )
  456.             ;
  457.         if ( value == 0 )
  458.             *breakOn = 0;
  459.         else
  460.             *breakOn = 1;
  461.     }
  462.     fflush(stdout);
  463. }
  464.  
  465. /*******************************************************************************
  466. ** SetOptions
  467. ********************************************************************************/
  468.  
  469. Boolean SetOptions(StateInfo* info, char* str)
  470. {
  471.     TOptMgmt    cmd;
  472.     OSStatus    err;
  473.     UInt8        buf[512];
  474.     
  475.     cmd.opt.buf        = buf;
  476.     cmd.opt.len        = 0;
  477.     cmd.opt.maxlen    = sizeof(buf);
  478.     cmd.flags        = T_NEGOTIATE;
  479.     
  480.     err = OTCreateOptions(kSerialName, &str, &cmd.opt);
  481.     
  482.     if ( err != kOTNoError )
  483.     {
  484.         printf("ERROR: OTCreateOptions returned %d\n", err);
  485.         fflush(stdout);
  486.         return false;
  487.     }
  488.     //
  489.     // Make the option management call to set stuff up
  490.     //
  491.     info->optMgmtDone = false;
  492.     err = OTOptionManagement(info->endPt, &cmd, &cmd);
  493.     if ( err != kOTNoError )
  494.     {
  495.         printf("ERROR: OptionManagement returned %d\n", err);
  496.         fflush(stdout);
  497.         return false;
  498.     }
  499.     else
  500.     {
  501.         while ( !info->optMgmtDone )
  502.             ;
  503.     }
  504.     return true;
  505. }
  506.  
  507. /*******************************************************************************
  508. ** SetParameters
  509. ********************************************************************************/
  510.  
  511. Boolean SetParameters(StateInfo* info)
  512. {
  513.     UInt32    baud;
  514.     UInt32    databits;
  515.     UInt32    stopbits;
  516.     UInt32    parity;
  517.     char    str1[4];
  518.     char    str2[4];
  519.     char    buf[256];
  520.     
  521.     printf("\nEnter parameters (BaudRate, [5 6 7 8 ], [N O E], [10 15 20]):\n");
  522.     fflush(stdout);
  523.     fflush(stdin);
  524.     clearerr(stdin);
  525.     if ( scanf("%lu , %1[5678], %1[NOEnoe], %lu", &baud, str1, str2, &stopbits) != 4 )
  526.     {
  527.         printf("ERROR: Bad format - aborted\n");
  528.         fflush(stdout);
  529.         fflush(stdin);
  530.         return false;
  531.     }
  532.     databits = str1[0] - '0';
  533.     
  534.     if ( str2[0] == 'o' || str2[0] == 'O' )
  535.         parity = kOTSerialOddParity;
  536.     else if ( str2[0] == 'e' || str2[0] == 'E' )
  537.         parity = kOTSerialEvenParity;
  538.     else 
  539.         parity = kOTSerialNoParity;
  540.  
  541.     if ( stopbits != 10 && stopbits != 15 && stopbits != 20 )
  542.     {
  543.         printf("ERROR: Bad format - aborted\n");
  544.         fflush(stdout);
  545.         return false;
  546.     }
  547.     sprintf(buf, "BaudRate=%lu DataBits=%lu StopBits=%lu Parity=%lu",
  548.                baud, databits, stopbits, parity);
  549.                
  550.     return SetOptions(info, buf);
  551. }
  552.  
  553. /*******************************************************************************
  554. ** GetKey
  555. ********************************************************************************/
  556.  
  557. #define    kCmdE    -2
  558. #define    kCmdQ    -3
  559. #define    kCmdB    -4
  560. #define kCmdI    -5
  561. #define kCmdT    -6
  562. #define kCmdP    -7
  563.  
  564. int GetKey()
  565. {
  566.     EventRecord    event;
  567.     
  568.     if ( GetNextEvent(keyDownMask | autoKeyMask, &event) )
  569.     {
  570.         char key = (char)(event.message & charCodeMask);
  571.         if ( event.modifiers & cmdKey )
  572.         {
  573.             if ( key == '.' )
  574.                 return -1;
  575.             if ( event.what != keyDown )
  576.                 return 0;
  577.             if ( key == 'e' || key == 'E' )
  578.                 return kCmdE;
  579.             if ( key == 'q' || key == 'Q' )
  580.                 return kCmdQ;
  581.             if ( key == 'b' || key == 'B' )
  582.                 return kCmdB;
  583.             if ( key == 't' || key == 'T' )
  584.                 return kCmdT;
  585.             if ( key == 'i' || key == 'I' )
  586.                 return kCmdI;
  587.             if ( key == 'p' || key == 'P' )
  588.                 return kCmdP;
  589.             SysBeep(5);
  590.             return 0;
  591.         }
  592.         if ( event.modifiers & optionKey )
  593.         {
  594.             SysBeep(5);
  595.             return 0;
  596.         }
  597.         if ( event.modifiers & controlKey )
  598.         {
  599.             if ( key > 0 && key <= 0x1f )
  600.                 return key;
  601.             SysBeep(5);
  602.             return 0;
  603.         }
  604.         if ( key >= 0x01 && key <= 0x7f )
  605.             return key;
  606.         SysBeep(5);
  607.     }
  608.     return 0;
  609. }
  610.  
  611. /*******************************************************************************
  612. ** DoTest
  613. ********************************************************************************/
  614.  
  615. void DoTest()
  616. {
  617.     StateInfo    info;
  618.     OSStatus    err;
  619.     
  620.     memset(&info, 0, sizeof(info));
  621.     
  622.     do
  623.     {
  624.         //
  625.         // Create a task scheduler so that we can "fprintf" stuff from our
  626.         // event handler.
  627.         //
  628.         info.sysTaskRef        = OTCreateSystemTask(SerialProcessProc, &info);
  629.         info.unbound        = true;
  630.         
  631.         if ( info.sysTaskRef == 0 )
  632.         {
  633.             printf("ERROR: Could not create System Task\n");
  634.             fflush(stdout);
  635.             break;
  636.         }
  637.         //
  638.         // Do a synchronous Open of the endpoint
  639.         //
  640.         info.endPt = OTOpenEndpoint(OTCreateConfiguration(kSerialName), 0, NULL, &err);
  641.     
  642.         if ( err != kOTNoError )
  643.         {
  644.             printf("ERROR: open of Serial Endpoint failed (%d).\n", err);
  645.             fflush(stdout);
  646.             break;
  647.         }
  648.  
  649.         //
  650.         // Install notifier we're going to use for testing. Pass the StateInfo
  651.         // structure as the 'context' value that the event handler will get back.
  652.         // (Note, can not use zero as the context value)
  653.         //
  654.         err = OTInstallNotifier(info.endPt, &SerialEventHandler, &info);
  655.         if ( err != kOTNoError )
  656.         {
  657.             printf("ERROR: InstallNotifier() failed with %d\n", err);
  658.             fflush(stdout);
  659.             break;
  660.         }
  661.  
  662.         OTSetAsynchronous(info.endPt);        // Ensure endpoint is async
  663.         OTSetNonBlocking(info.endPt);        // Ensure endpoint is and non-blocking
  664.  
  665.         do
  666.         {
  667.             Boolean    breakOn;
  668.             ShowEndpointOptions(&info, &breakOn);
  669.  
  670.             //
  671.             // Ask user what to do
  672.             //
  673.             int        testNum = 0;
  674.             Boolean    echo = true;
  675.  
  676.             printf("\nChoose Test:\n");
  677.             printf("    1) Connect to remote node\n");
  678.             printf("    2) Listen and accept connection from remote node\n");
  679.             printf("    3) Set Parameters\n");
  680.             printf("    4) Quit\n");
  681.             fflush(stdout);
  682.             
  683.             while ( true )
  684.             {
  685.                 int        c;
  686.                 
  687.                 switch ( c = GetKey() )
  688.                 {
  689.                     case 0:
  690.                         break;
  691.                         
  692.                     case -1:
  693.                         c = '4';
  694.                         /* fall thru */
  695.                         
  696.                     case '1':
  697.                     case '2':
  698.                     case '3':
  699.                     case '4':
  700.                         testNum = c - '0';
  701.                         printf("%c\n", c);
  702.                         fflush(stdout);
  703.                         break;
  704.                     
  705.                     default:
  706.                         SysBeep(5);
  707.                         break;
  708.                 }
  709.                 if ( testNum != 0 )
  710.                     break;
  711.             }
  712.  
  713.             if ( testNum == 4)
  714.                 break;
  715.             //
  716.             // We'll start off the bind, and let the asynchronous event handler take it
  717.             // from there.
  718.             //
  719.             info.acceptDone = false;
  720.             info.passconDone= false;
  721.             info.ready        = false;
  722.             info.error        = kOTNoError;
  723.             info.connect    = testNum == 1;
  724.             {
  725.                 TBind    bind;
  726.                 
  727.                 bind.addr.buf    = NULL;
  728.                 bind.addr.len    = 0;
  729.                 bind.qlen        = info.connect ? 0 : 1;
  730.  
  731.                 err = OTBind(info.endPt, &bind, NULL);
  732.                 if ( err != kOTNoError )
  733.                 {
  734.                     printf("ERROR: Bind returned %d\n", err);
  735.                     fflush(stdout);
  736.                     break;
  737.                 }
  738.             }
  739.             
  740.             if ( testNum == 3 )
  741.             {
  742.                 SetParameters(&info);
  743.                 OTUnbind(info.endPt);
  744.                 continue;
  745.             }
  746.                 
  747.             Boolean aborted = false;
  748.             if ( !info.connect )
  749.             {
  750.                 printf("Waiting for incoming connection\n");
  751.                 printf("Press mouse button to abort\n");
  752.                 fflush(stdout);
  753.             }
  754.             while ( !info.ready )
  755.             {
  756.                 if ( Button() )
  757.                 {
  758.                     while ( Button() )
  759.                         ;
  760.                     aborted = true;
  761.                     break;
  762.                 }
  763.             }
  764.             if ( info.error != kOTNoError )
  765.                 break;
  766.             
  767.             if ( !aborted )
  768.             {
  769.                 if ( !info.connect )
  770.                     printf("Incoming connection received and accepted\n\n");
  771.                 printf("Command-. aborts                   Command-E toggles echo on and off\n");
  772.                 printf("Command-B toggles Break            Command-T turns break on for 5 seconds\n");
  773.                 printf("Command-I shows endpoint options   Command-P changes parameters\n");
  774.                 printf("=========================================================================\n\n");
  775.                 fflush(stdout);
  776.                 while ( true )
  777.                 {
  778.                     char    buf[20];
  779.                     size_t    idx = 0;
  780.                     int        c;
  781.                     
  782.                     SystemTask();
  783.                     while ( (c = GetKey()) != 0 )
  784.                     {
  785.                         if ( c < 0 )
  786.                         {
  787.                             Boolean    ok = true;
  788.                             switch ( c )
  789.                             {
  790.                                 case kCmdE:    echo = !echo; break;
  791.                                 case kCmdB:    DoBreak(&info, &breakOn, false); break;
  792.                                 case kCmdT:    DoBreak(&info, &breakOn, true); break;
  793.                                 case kCmdI: ShowEndpointOptions(&info, &breakOn); break;
  794.                                 
  795.                                 case kCmdP:    
  796.                                     ShowEndpointOptions(&info, &breakOn);
  797.                                     if ( SetParameters(&info) )    
  798.                                         ShowEndpointOptions(&info, &breakOn);
  799.                                     break;
  800.                                     
  801.                                 case kCmdQ:
  802.                                 default:
  803.                                     ok = false;
  804.                                     break;
  805.                             }
  806.                             if ( ok )
  807.                                 continue;
  808.                             break;
  809.                         }
  810.                         if ( echo )
  811.                         {
  812.                             if ( c >= 0x20 && c <= 0x7f )
  813.                                 printf("%c", c);
  814.                             else if ( c == 0x0a || c == 0x0d )
  815.                                 printf("\n");
  816.                             fflush(stdout);
  817.                         }
  818.                         buf[idx++] = c;
  819.                     }
  820.                     if ( c < 0 )
  821.                         break;
  822.  
  823.                     OTResult    sent;
  824.                     char*        toSend = buf;
  825.                     
  826.                     while ( true )
  827.                     {
  828.                         sent = OTSnd(info.endPt, toSend, idx, T_MORE);
  829.                         if ( sent < 0 && sent != kOTFlowErr )
  830.                         {
  831.                             printf("\n*****\n     ERROR: Snd() return error %d\n*****\n", err);
  832.                             fflush(stdout);
  833.                             break;
  834.                         }
  835.                         if ( sent == idx )
  836.                             break;
  837.                         if ( sent > 0 )
  838.                         {
  839.                             toSend    += sent;
  840.                             idx        -= (size_t)sent;
  841.                         }
  842.                     }
  843.                 }
  844.             }
  845.             printf("Disconnecting endpoint\n");
  846.             fflush(stdout);
  847.             //
  848.             // If SndDisconnect returns an error, it's probably because
  849.             // we're listening and haven't gotten a connection yet.
  850.             //
  851.             if ( OTSndDisconnect(info.endPt, NULL) != kOTNoError )
  852.                 OTUnbind(info.endPt);
  853.             while ( !info.unbound )
  854.                 ;
  855.                 
  856.         } while ( true );
  857.     } while ( false );
  858.  
  859.     //
  860.     // Clean up the endpoint we allocated
  861.     //
  862.     if ( info.endPt != NULL )
  863.     {
  864.         OTResult state = OTGetEndpointState(info.endPt);
  865.         
  866.         if ( state == T_DATAXFER || state == T_INCON || state == T_OUTCON )
  867.         {
  868.             printf("Disconnecting endpoint\n");
  869.             fflush(stdout);
  870.             OTSndDisconnect(info.endPt, NULL);
  871.         }
  872.         else if ( state == T_IDLE )
  873.         {
  874.             printf("Unbinding endpoint\n");
  875.             fflush(stdout);
  876.             OTUnbind(info.endPt);
  877.         }
  878.         while ( !info.unbound )
  879.             ;
  880.         OTRemoveNotifier(info.endPt);
  881.         OTSetSynchronous(info.endPt);
  882.         OTSetBlocking(info.endPt);
  883.         err = OTCloseProvider(info.endPt);
  884.         if ( err != kOTNoError )
  885.         {
  886.             printf("ERROR: CloseEndpoint returned %d\n", err);
  887.             fflush(stdout);
  888.         }
  889.     }
  890.     OTDestroySystemTask(info.sysTaskRef);
  891. }
  892.  
  893. /*******************************************************************************
  894. ** Initialize Open Transport and call DoTest function
  895. ********************************************************************************/
  896.  
  897. main(int, char**) 
  898. {
  899.     InitGraf(&qd.thePort);                    // initialize quickdraw so we can use regions
  900.     
  901.     printf("SerialSample showing usage of Serial endpoints.\n\n");
  902.     fflush(stdout);
  903.     //
  904.     // Initialize Open Transport
  905.     //
  906.     if ( InitOpenTransport() == kOTNoError )
  907.     {
  908.         //
  909.         // Run the test
  910.         //
  911.         DoTest();
  912.         
  913.         //
  914.         // Shut down Open Transport.
  915.         // Not strictly necessary since it patches _ExitToShell and will
  916.         // clean us up anyway.
  917.         //
  918.         CloseOpenTransport();
  919.         
  920.         printf("\n\nDone\n");
  921.         fflush(stdout);
  922.             
  923.         return 0;
  924.     }
  925.     return 1;
  926. };
  927.  
  928.